package 反射;

/*
反射源码解析
一、如何使用反射
二、源码与字节码
   2.1 字节码知识
   2.1 类的组成
       2.1.1 辅助类
             2.1.1.1 AnnotatedElement
             2.1.1.2 Type
             2.1.1.3 AnnotatedType
             2.1.1.4 AccessibleObject
             2.1.1.5 Modifier 修饰符
       2.1.2. Member 成员
             2.1.2.1 Field 成员
             2.1.2.2 executable 成员
                     2.1.2.2.1. method 成员
                     2.1.2.2.2. Constructor 成员
       2.1.3 数组和枚举
             2.1.3.1 数组
             2.1.3.2 枚举
       2.1.4 其他
             2.1.4.1 静态代理
             2.1.4.1 动态代理
   2.2 class 类
       2.2.1 类型判断
       2.2.1 类的注解
       2.2.3 类的信息
三、反射机制
初衷是对反射的使用和字节码了解后，产生了想探究更深层次的原理，这就绕不过对源码的分析。了解后，发现对源码的分析可以分为两块：
   -源码和字节码的对应关系。
   -运行时反射机制的调用。
想要更深刻理解，最好先了解字节码知识，jvm类的加载机制。

一、如何使用反射
使用看官网的教程就可以，大概描述下。
首先java中的任何对象，加载进jvm，都有一个对应的Class对象（和对象存在映射关系）。教程分了如下几步
   -如何取出对象的Class，比如使用 getClass()函数
   -对象的成员，可以分为Field,method,constructors 。如何获取对象的成员并如何使用。
   -特殊类型: 数组和枚举。
看完教程，恭喜你学会了使用反射机制。

二、源码与字节码
从源码出发，一层一层的讲解。探究是如何从字节码出发，看java代码是如何编排字节码，最终实现了反射这个功能。

2.1 字节码知识
想更一步了解的可以参考，这里只是简单说明必要的。
字节码知识 & 《深入理解jvm字节码》

.java编译后的文件.class的内容是一个表结构

速记     类型         名称                 说明             长度
my	    u4	       magic	      魔数，识别Class文件格式	4个字节
very	u2	   minor_version	      副版本号            2个字节
        u2	   major_version          主版本号            2个字节
cute	u2	constant_pool_count      常量池计算器          2个字节
      cp_info   constant_pool	       常量池             n个字节
animal	u2      access_flags         访问标志             2个字节
turn	u2      this_class             类索引             2个字节
savage	u2      super_class           父类索引            2个字节
in	    u2      interfaces_count     接口计数器            2个字节
        u2      interfaces           接口索引集合           2个字节
full    u2      fields_count          字段个数             2个字节
     field_info  fields              字段集合              n个字节
moon    u2      methods_count        方法计数器            2个字节
    method_info methods               方法集合            n个字节
areas   u2      attributes_count    附加属性计数器          2个字节
   attribute_info attributes         附加属性集合          n个字节
my very cute animal turn savage in full moon areas速记类文件结构

2.1 类的组成

这是 java.lang.reflect 类的继承关系。不难看出设计上Field,method,constructors等核心成员，继承于一些顶层的类AnnotatedElement,type等，需要先讲这些类。

2.1.1 辅助类
2.1.1.1 AnnotatedElement
作用就是运行时获取注解。
注解的字节码结构
class自身和class的成员都可以标注注解，这个类就是统一的在运行时获取被标注的注解。

AnnotatedElement
isAnnotationPresent(Class<? extends Annotation>)  boolean
getAnnotation(Class<T>)                              T
getAnnotations()                                 Annotation[]
getAnnotationsByType(Class<T>)                      T[]
getDeclaredAnnotation(Class<T>)                      T
getDeclaredAnnotationsByType(Class<T>)              T[]
getDeclaredAnnotations()                        Annotation[]

说明:	
1.boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)   接受一个注解，运行时判断注解的类型是
不是当前的注解。比如：TestInfo.class.getMethod(“born”).isAnnotationPresent(StudentInfo.class)判断born方法上的注解
是不是StudentInfo.class注解

2.Annotation[] getAnnotations()	获取所有的注解

2.1.1.2 Type
java中的type介绍
表示一个类的类型，一个类是泛型，基本类型，以及如何表示。

ParameterizedType
参数化类型，即泛型；例如：List、Map<K,V>等带有参数化的对象;

public interface ParameterizedType extends Type {
 // 获取<>中的实际类型， 比如 List<T>的T
 Type[] getActualTypeArguments();
 // 获取<> 之前的类型，比如 List<T>的List
 Type getRawType();
 // 获取拥有者的类型 O<T>.I<S>,那么就返回 O<T>
 Type getOwnerType();
 }

TypeVariable
类型变量，即泛型中的变量；例如：T、K、V等变量，可以表示任何类；在这需要强调的是，TypeVariable代表着泛型中的变量，而ParameterizedType则代表整个泛型；

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement{
// 一个形如TypeVariable<D extends GenericDeclaration> extends Type的泛型
 //  返回上例中的 extends的右侧，没有就返回Object
 Type[] getBounds();
 // 返回泛型
 D getGenericDeclaration();
 // 返回名称 D
 String getName();
 // 返回注解的上界
 AnnotatedType[] getAnnotatedBounds();
}

GenericArrayType
泛型数组类型，用来描述ParameterizedType、TypeVariable类型的数组；即List[] 、T[]等；

public interface GenericArrayType extends Type {
    //返回数组的元素类型A<T>(A<T>[])或T(T[])
	 Type getGenericComponentType();

WildcardType

WildcardType是Type的子接口，用于描述形如“? extends classA” 或 “？super classB”的“泛型参数表达式”。
List<? extends String>这种类型就叫WildcardType

public void hello( List<? extends String>  o  ){}
```java
public interface WildcardType extends Type {
     //获得泛型表达式的上界，上界 extends
	 Type[] getUpperBounds();
	 //获得泛型表达式的下限，下限 super
	 Type[] getLowerBounds();
	 }

2.1.1.3 AnnotatedType
和type类型对应，但是注解形式的


2.1.1.4 AccessibleObject
设置权限，Method等都继承了这个对象

比如将权限设置为可以获取

    Method born = TestInfo.class.getMethod("born");
        born.setAccessible(true);

setAccessible的实现

public void setAccessible(boolean flag) throws SecurityException {
       SecurityManager sm = System.getSecurityManager();
       // 检查是有权限设置sm.checkPermission(ACCESS_PERMISSION);
       if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
       setAccessible0(this, flag);
}

2.1.1.5 Modifier 修饰符
比如一个方法定位为public static void hello，那么根据

method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

u2 access_flags 就是在字节码中放置修饰符的位置。
2byte的修饰符，每一位的含义都不同。比如 public static的含义是—0x0001 |0x0008 即二进制末尾为 XXX1001。

这个是method的flag表

Flag Name	Value	Interpretation
ACC_PUBLIC	0x0001	Declared public; may be accessed from outside its package.
ACC_PRIVATE	0x0002	Declared private; accessible only within the defining class.
ACC_PROTECTED	0x0004	Declared protected; may be accessed within subclasses.
ACC_STATIC	0x0008	Declared static.
ACC_FINAL	0x0010	Declared final; must not be overridden (§5.4.5).
ACC_SYNCHRONIZED	0x0020	同步方法Declared synchronized; invocation is wrapped by a monitor use.
ACC_BRIDGE	0x0040	A bridge method, generated by the compiler.
ACC_VARARGS	0x0080	Declared with variable number of arguments.
ACC_NATIVE	0x0100	Declared native; implemented in a language other than Java.
ACC_ABSTRACT	0x0400	Declared abstract; no implementation is provided.
ACC_STRICT	0x0800	Declared strictfp; floating-point mode is FP-strict.
ACC_SYNTHETIC	0x1000	是否是jvm合成的方法，Declared synthetic; not present in the source code.
Modifier 就是代表了修饰符，本质是一个 代表了修饰符的 int 和额外的工具方法。比如判断是否是public

// mod是目标类的修饰符，和0X0001 做&预算
 public static boolean isPublic(int mod) {
        return (mod & PUBLIC) != 0;
    }

内部的所有方法


2.1.2. Member 成员
具备三个子类Field，Method, Constructor

源码

public
interface Member {

    //标识所有的公共成员，包含父类
    public static final int PUBLIC = 0;
	//是否是声明过的类
    public static final int DECLARED = 1;
    //获取对象所所属的类型
    public Class<?> getDeclaringClass();
    //成员的名称
    public String getName();
    //返回修饰符
    public int getModifiers();
    //是否是合成类
    public boolean isSynthetic();

举例
Method是Member的子类

Method born = TestInfo.class.getMethod("born");
born.setAccessible(true);
System.out.println(born.getDeclaringClass());
System.out.println(born.getName());
System.out.println(born.getModifiers());
System.out.println(born.isSynthetic());

打印

class bytecode.annotation.TestInfo //类名
born // 方法名
1 // public修饰符
false // 不是合成类

2.1.2.1 Field 成员
Field字节码对应的java类

字节码结构体

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

内部方法
多但都是工具方法


demo
获取field信息
获取class信息
获取注解信息
获取filed对应的值

public class TestInfo {

    @StudentInfo(age = 13, name = "sun")
    String address = "xian";

    @StudentInfo(age = 0, name = "baby")
    public void born() {
        System.out.println("human born");
    }


    public static void main(String[] args) throws Exception {
        TestInfo ti = new TestInfo();
        // 获取注解
        Field address = TestInfo.class.getDeclaredField("address");
        // get 这里是String 对象，如果是int还可以使用getInt(ti)
        String addressValue = (String)address.get(ti);
        System.out.println(addressValue);
        // 基本信息
        System.out.println(address.toString());
        // 注解信息
        System.out.println(address.getAnnotations()[0].toString());
        // 类型名
        System.out.println(address.getAnnotatedType().getType().getTypeName()); 
    }
}

可以看出包含基本信息


2.1.2.2 executable 成员

和field大同小异
除了修饰符的查询之外，额外还多了参数的获取匹配。
毕竟参数是方法和构造很重要的一部分。
示例

public class TestInfo {

    @StudentInfo(age = 13, name = "sun")
    String address = "xian";

    @StudentInfo(age = 0, name = "baby")
    public void born(String name ) {
        System.out.println("human born ");
    }


    public static void main(String[] args) throws Exception {
        TestInfo ti = new TestInfo();
        ti.born("ok");
        Method born = TestInfo.class.getDeclaredMethod("born",String.class);
        System.out.println(born.getParameterTypes()[0]);
     }
}
输出
class java.lang.String

2.1.2.2.1. method 成员
没有过多特殊的

2.1.2.2.2. Constructor 成员
类的构造器，特殊的方法
和method的区别是可以用来创建对象。
.class.newInstance实际上就是先获取类型的无参数构造器对象，然后调用.newInstance()方法。

 TestInfo.class.newInstance();//   TestInfo.class.getConstructor().newInstance()
1
除了无参数之外，还可以带参数获取指定构造器。
TestInfo.class.getConstructor(String.class,Integer.class).newInstance();

2.1.3 数组和枚举
2.1.3.1 数组
这个比较好理解一点，array对象就是数组，被算为一个特殊的Field。集合不是。


public class TestInfo {

    List<String> list = new ArrayList<>();
    String[] array = new String[10];

    public static void main(String[] args) throws Exception {

        TestInfo ti = new TestInfo();
        // 数组
        Field list = TestInfo.class.getDeclaredField("list");
        Field array = TestInfo.class.getDeclaredField("array");
        // 不是
        System.out.println(list.getType().getTypeName() + " is array :" + list.getType().isArray());
        // 是
        System.out.println(array.getType().getTypeName() + " is array :" + array.getType().isArray());

    }

输出

java.util.List is array :false
java.lang.String[] is array :true

还有其他一些方法

Object newInstance(Class<?> componentType, int length)
创建一个数组，
Object get(Object array, int index)
获取数据的索引对应的值
//String arr = new String[10];
Object arr = Array.newInstance(String.class,10);
// arr[0] = "demo"
Array.set(arr,0,"demo");
// System.out.println(arr[0]);
System.out.println(Array.get(arr,0));

2.1.3.2 枚举
使用
简单的枚举类型

    enum Nubmers {one, two, three}

    public static void main(String[] args) {
        Nubmers one = Nubmers.valueOf("one");
        System.out.println(one.ordinal());
        System.out.println(one.name());
    }

复杂一点的枚举类

枚举类不进可以赋值，还可以定义函数

  public enum Sex {
        male("man", 10),
        female("woman", 11);
        String humanType;
        int id;

        private Sex(String humanType, int id) {
            this.humanType = humanType;
            this.id = id;
        }

        public void print() {
            System.out.println(humanType + "  " + id);
        }
    }
    public static void main(String[] args) {

        Sex male = Sex.valueOf("male");
        System.out.println(male.ordinal());
        System.out.println(male.name());
        male.print();
    }

反射
提供了三个api

Class.isEnum()
判断是不是一个枚举类
Class.getEnumConstants()
获取枚举类型常量
java.lang.reflect.Field.isEnumConstant()
filed级别的接口判断是不是一个枚举常量
public class Demo {

    Sex sex = Sex.male;

    public enum Sex {
        male("man", 10),
        female("woman", 11);
        String humanType;
        int id;

        private Sex(String humanType, int id) {
            this.humanType = humanType;
            this.id = id;
        }

        public void print() {
            System.out.println(humanType + "  " + id);
        }
    }


    public static void main(String[] args) throws Exception {

 
        // 反射API
        Sex human = Sex.male;
        System.out.println(human.getClass().isEnum());
        Sex[] sexs = human.getClass().getEnumConstants();
        System.out.println(sexs[1].name());
        // 类内枚举类型的判断
        Field field = Demo.class.getDeclaredField("sex");
        System.out.println(field.getType().isEnum());

    }
}

实现，不难看出是使用getModifiers()获取修饰符，来判断是不是枚举

  public boolean isEnum() {
        // An enum must both directly extend java.lang.Enum and have
        // the ENUM bit set; classes for specialized enum constants
        // don't do the former.
        return (this.getModifiers() & ENUM) != 0 &&
        this.getSuperclass() == java.lang.Enum.class;
    }

2.1.4 其他
proxy 代理也是反射包的，这个归类为其他。

2.1.4.1 静态代理
静态代理是一种模式，不涉及任何反射的知识。需要预先把需要的类定义好
公有接口

public interface Hello {
    default public void welcome() {
        System.out.println("china welcome!");
    };
}

实现子类

public class BJHello implements Hello {
    public void welcome() {
        System.out.println("BJ welcome!");
    };

}

代理类
通过注入真正的实现，委托调用方法 &测试

public class StaticProxy implements Hello {
    Hello hello;

    public StaticProxy(Hello hello) {
        this.hello = hello;
    }

    public void welcome() {
        System.out.println("static proxy!");
        hello.welcome();
    }


    public static void main(String[] args) {
        Hello hello =new StaticProxy(new BJHello());
        hello.welcome();
    }
}

2.1.4.1 动态代理
顾明思议，代理类不会预先定义要动态生成。需要使用反射的函数。
这里重点是用

InvocationHandler
Proxy.newProxyInstance;
第一参数是加载用的classloader，第二个参数接口，第三个是自定义的代理，可以自定义动作。
public class DynamicProxy implements InvocationHandler {
    private Object target = null;

    DynamicProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前");
        method.invoke(target, args);
        System.out.println("代理后");
        return null;
    }

    public static void main(String[] args) {
        Hello hello = new BJHello() ;
        DynamicProxy dyProxy = new DynamicProxy(hello);
        Hello helloProxy = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), new Class[]{Hello.class}, dyProxy);
        helloProxy.welcome();
    }


}

打印

代理前
BJ welcome!
代理后
1
2
3
2.2 class 类
终于到了重头戏，这是一个自下而上讲的例子。之所以这么讲会发现，class使用前面的基础类实现的。解析class的过程不用穿插讲 成员类的作用。



.class 是.java编译后的二进制文件。而Class是这个二进制文件的数据结构。每当一个.class 文件被jvm加载，那么就会对应生成一个Class对象。可以利用这个对象对实例进行操作，这也就是反射的机制。

// 获取注解
 
 Field address = TestInfo.class.getDeclaredField("address");
// get 这里是String 对象，如果是int还可以使用getInt(ti)
TestInfo ti = new TestInfo();
 String addressValue = (String) address.get(ti);

从这类子不难看出，TestInfo.class.getDeclaredField("address");,就是获得Filed的定义，跟实例无关。
真正要获取实例的值时，要传入一个实例的引用get(ti);,这也就是ti参数的意义。

开发时获取别人开发的对象有时会很困难，甚至要改动老的代码去嵌入自己的逻辑。但是有了反射后，仅仅需要得到别人一个传入的实例句柄。更多的是，不需要改变别人的代码，就可以为代码织入额外的动作，比如代理。

下面讲的话，从Class继承的几个类开始讲

2.2.1 类型判断
内置三个常量，用来判断是枚举类型，还是注解，还是合成类

private static final int ANNOTATION= 0x00002000;
private static final int ENUM      = 0x00004000;
private static final int SYNTHETIC = 0x00001000;

一堆方法

方法	描述	
boolean isInstance(Object obj)	判断是否是实例	
boolean isInterface()	判断是否是接口	
boolean isArray()	判断是否是数组，比如String []	
boolean isPrimitive()	判断是否是基本类型，Integer	
boolean isAnnotation	判断是注解	
boolean isSynthetic()	判断是否是合成类	
boolean isAssignableFrom(Class<?> cls)	判断是否是继承关系	
boolean isEnum()	判断是否是枚举	
实现分三类

本地方法 比如public native boolean isAssignableFrom(Class<?> cls)
和修饰符
public boolean isAnnotation() {
		// getModifiers就是获取修饰符一个2byte的字段，使用int表示
        return (getModifiers() & ANNOTATION) != 0;
}

2.2.1 类的注解
核心一个方法

方法	描述	
public Annotation[] getAnnotations()	获取类上的注解	
getAnnotationsByType(Class<A> annotationClass)	获取指定类型的注解	
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)	判断类是否具备这个传入的注解	前面有例子
AnnotatedType getAnnotatedSuperclass()	获取extends接口的类型	
AnnotatedType getAnnotatedInterfaces()	获取implement接口的类型	
getAnnotations()
 public Annotation[] getDeclaredAnnotations()  {
        return AnnotationParser.toArray(annotationData().declaredAnnotations);
    }

AnnotationData
可以看出class文件使用了一个Map结构来存储所有的注解

    private static class AnnotationData {
        final Map<Class<? extends Annotation>, Annotation> annotations;
        final Map<Class<? extends Annotation>, Annotation> declaredAnnotations;

        // Value of classRedefinedCount when we created this AnnotationData instance
        final int redefinedCount;

        AnnotationData(Map<Class<? extends Annotation>, Annotation> annotations,
                       Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
                       int redefinedCount) {
            this.annotations = annotations;
            this.declaredAnnotations = declaredAnnotations;
            this.redefinedCount = redefinedCount;
        }
    }

getAnnotatedSuperclass() & getAnnotatedInterfaces()
可以理解为是，每个类型都会生成一个注解。这两个结构就是为了获取父类和实现的接口
Demo
@StudentInfo(age = 13, name = "sun")
public class TestInfo extends TypeTest implements Hello {

    public static void main(String[] args) throws Exception {

        TestInfo ti = new TestInfo();
        System.out.println(ti.getClass().getAnnotatedSuperclass().getType().getTypeName());
        for (AnnotatedType a : ti.getClass().getAnnotatedInterfaces()) {
            System.out.println(a.getType().getTypeName());
        }
}

打印
只打印了父类和接口，注解没有打印，需要使用getAnnotations()去取

bytecode.Type.TypeTest
bytecode.proxy.statics.Hello


2.2.3 类的信息
这个类的字节码

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

对号入座这些方法

  // classloader
        System.out.println("classloader :" + TestInfo.class.getClassLoader().getClass().getTypeName());
        // 本类的名称
        System.out.println("classname :" + TestInfo.class.getCanonicalName());
        // 获取内部类
        for (Class c : TypeTest.class.getClasses()) {
            System.out.println("subclass - " + c.getTypeName());
        }
        // 获取父类
        System.out.println("supper classname :" + TestInfo.class.getSuperclass().getTypeName());
        // 获取实现的接口
        System.out.println("interfaces :" + TestInfo.class.getInterfaces()[0].getTypeName());
        // 获取构造器
        System.out.println("constructor :" + TestInfo.class.getConstructors().getClass().getTypeName());
        // 获取签名
        System.out.println("Signer :" + TestInfo.class.getSigners());
        System.out.println("Modifier :" + TestInfo.class.getModifiers());
        // 获取数组的类型
        String[] array = new String[1];
        System.out.println("array type :" +array.getClass().getComponentType());

输出

classloader :sun.misc.Launcher$AppClassLoader
classname :bytecode.annotation.TestInfo
subclass - bytecode.Type.TypeTest$Nested
supper classname :bytecode.Type.TypeTest
interfaces :bytecode.proxy.statics.Hello
constructor :java.lang.reflect.Constructor[]
Signer :null
Modifier :1
array type :class java.lang.String

三、反射机制
.class 是.java编译后的二进制文件。而Class是这个二进制文件的数据结构。每当一个.class 文件被jvm加载，那么就会对应生成一个Class对象。可以利用这个对象对实例进行操作，这也就是反射的机制。
*/